package com.xbongbong.formula.enums;

/**
 * @author: wufeng
 * @date: 2018/6/28 18:43
 * @desrcption: 数学函数枚举类
 */
public enum MathEnum {

    /*------数学函数 22个--------*/
    /**返回参数的平均值（算术平均值）*/
    AVERAGE("math", "AVERAGE"),
    /**统计参数个数。*/
    COUNT("math", "COUNT"),
    /**统计满足条件的参数个数。**/
    COUNTIF("math", "COUNTIF"),
    /**返回将参数 number 向上舍入（沿绝对值增大的方向）为最接近的指定基数的倍数。*/
    CEILING("math", "CEILING"),
    /**返回一组值中的最大值。*/
    MAX("math", "MAX"),
    /**返回一组值中的最小值。*/
    MIN("math", "MIN"),
    /**返回数据集中第k个最大值。*/
    LARGE("math", "LARGE"),
    /**返回数据集中第k个最小值。*/
    SMALL("math", "SMALL"),
    /**返回数字的绝对值。**/
    ABS("math", "ABS"),
    /**将数字四舍五入到指定的位数。*/
    ROUND("math", "ROUND"),
    /**
     * 语法: ROUNDUP(number, num_digits)
     * 说明：number为要处理的数字，num_digits为指定小数位数
     * • ROUNDUP 的行为与 ROUND 相似，所不同的是它始终将数字进行向上舍入。
     * • 如果 num_digits 大于 0（零），则将数字向上舍入到指定的小数位数。
     * • 如果 num_digits 为 0，则将数字向上舍入到最接近的整数。
     * • 如果 num_digits 小于 0，则将数字向上舍入到小数点左边的相应位数。
     */
    ROUNDUP("math", "ROUNDUP"),
    /**
     * 语法: ROUNDDOWN(number, num_digits)
     * 说明：number为要处理的数字，num_digits为指定小数位数
     * • ROUNDDOWN 的行为与 ROUND 相似，所不同的是它始终将数字进行向下舍入。
     * • 如果 num_digits 大于 0（零），则将数字向下舍入到指定的小数位数。
     * • 如果 num_digits 为 0，则将数字向下舍入到最接近的整数。
     * • 如果 num_digits 小于 0，则将数字向下舍入到小数点左边的相应位数。
     */
    ROUNDDOWN("math", "ROUNDDOWN"),
    /**将参数number向下舍入（沿绝对值减小的方向）为最接近的significance的倍数。*/
    FLOOR("math", "FLOOR"),
    /**将数字向下舍入到最接近的整数。*/
    INT("math", "INT"),
    /***根据指定底数返回数字的对数。*/
    LOG("math", "LOG"),
    /**返回两数相除的余数。 结果的符号与除数相同。*/
    MOD("math", "MOD"),
    /**返回数字乘幂的结果。*/
    POWER("math", "POWER"),
    /**函数使所有以参数形式给出的数字相乘并返回乘积。*/
    PRODUCT("math", "PRODUCT"),
    /**返回正的平方根。*/
    SQRT("math", "SQRT"),
    /**函数使所有以参数形式给出的数字相加并返回和。*/
    SUM("math", "SUM"),
    /**
     * SUMIF(value1, [value2], …, criteria)
     * 统计满足条件的参数个数。
     * 例如：
     * • SUMIF([1,2,3,4], “>2”)，结果为7
     * • SUMIF([1,2,3,4], “!=2”)，结果为8
     * • SUMIF([1,2,3,4], “>=1”)，结果为9
     * */
    SUMIF("math", "SUMIF"),
    /**在给定的数组中，将数组间对应的元素相乘，并返回乘积之和。*/
    SUMPRODUCT("math", "SUMPRODUCT"),
    /**将数字舍入到指定的小数位数，以十进制数格式对该数进行格式设置，并以文本形式返回结果。*/
    FIXED("math", "FIXED"),
    /**返回大于等于 0 且小于 1 的均匀分布随机实数。每一次触发计算都会变化。*/
    RAND("math", "RAND"),
    UPPERMONEY("math", "UPPERMONEY"),
    /** 精确计算和 **/
    ADD("math", "ADD"),
    /** 精确计算差 **/
    SUBTRACT("math", "SUBTRACT"),
    /** 精确计算积 **/
    MULTIPLY("math", "MULTIPLY"),
    /** 精确计算商 **/
    DIVIDE("math", "DIVIDE"),

    /*---逻辑函数 8个--*/
    /**在参数组中，任何一个参数逻辑值为false，即返回false；只有当所有参数逻辑值为true，才返回true。*/
    AND("logic", "AND"),
    /**在参数组中，任何一个参数逻辑值为true，即返回true；只有当所有逻辑参数值为false，才返回false。*/
    OR("logic", "OR"),
    /**返回逻辑值false。*/
    FALSE("logic", "FALSE"),
    /**返回逻辑值true*/
    TRUE("logic", "TRUE"),
    /**判断一个条件能否满足；如果满足返回一个值，如果不满足则返回另外一个值。*/
    IF("logic", "IF"),
    /**NOT(logical)把括号里为true的值变成false，括号里为false的值变为true。*/
    NOT("logic", "NOT"),
    /**返回所有参数的异或值。*/
    XOR("logic", "XOR"),
    /**判断值是否为空字符串、空对象或者空数组。*/
    ISEMPTY("logic", "ISEMPTY"),

    /* --------文本函数  16个------------*/
    /**将多个文本字符串合并成一个文本字符串*/
    CONCATENATE("text", "CONCATENATE"),
    /**返回计算机字符集的数字代码所对应的字符。*/
    CHAR("text", "CHAR"),
    /**比较两个字符串是否完全相同（区分大小写）。完全相同则返回true，否则返回false*/
    EXACT("text", "EXACT"),
    /**从一个文本字符串的第一个字符开始返回指定个数的字符。*/
    LEFT("text", "LEFT"),
    /**返回文本字符串中的字符个数。*/
    LEN("text", "LEN"),
    /**将一个文本字符串中的所有大写字母转换为小写字母。*/
    LOWER("text", "LOWER"),
    /**根据指定的字符数，将部分文本字符串替换为不同的文本字符串。*/
    REPLACE("text", "REPLACE"),
    /**将文本重复一定次数。*/
    REPT("text", "REPT"),
    /**在第二个文本字符串中查找第一个文本字符串，并返回第一个文本字符串的起始位置的编号，该编号从第二个文本字符串的第一个字符算起。返回0则表示未查找到。*/
    SEARCH("text", "SEARCH"),
    /**返回文本值中最右边的字符。*/
    RIGHT("text", "RIGHT"),
    /**将文本按指定字符串分割成数组。*/
    SPLIT("text", "SPLIT"),
    /**1、删除字符串首尾的空格。2、如果字符串内部存在连续多个空格，还会删除至仅剩一个空格。*/
    TRIM("text", "TRIM"),
    /**将一个文本字符串中的所有小写字母转换为大写字母。*/
    UPPER("text", "UPPER"),
    /**返回文本字符串中从指定位置开始的特定数目的字符*/
    MID("text", "MID"),
    /**将数字转为文本*/
    TEXT("text", "TEXT"),
    /**将文本转化为数字*/
    VALUE("text", "VALUE"),
    /** 返回一个拼接的字符串*/
    JOIN("math", "JOIN"),
    /** 对字符串进行MD5加密*/
    MD5("math", "MD5"),
    /** 对字符串进行SHA256加密*/
    BASE64("math", "BASE64"),
    /** 对字符串进行SHA256加密*/
    SHA256("math", "SHA256"),
    /*----------日期函数  25个----------*/
    /**
     * YEARS（年差）
     * 说明：返回两个日期之间的年数差值，精确到两位小数。end_date为结束日期，start_date为开始日期
     * 例如：录入【当前时间】、【出生时间】，通过YEARS函数自动填入【年龄】。
     */
    YEARS("years", "YEARS"),
    /**
     * DAYS函数可以返回两个日期之间相差的天数。
     * 语法：DAYS(end_date,start_date)
     * 说明：返回两个日期之间的天数差值，精确到两位小数。end_date为结束日期，start_date为开始日期
     * 例如：录入【生产时间】、【到期时间】，通过DAYS函数自动填入【有效天数】。
     */
    DAYS("date", "DAYS"),
    /**
     * 语法：HOURS(end_time,start_time)
     * 说明：返回两个时间之间的小时数，精确到两位小数。end_time为结束时间，start_time为开始时间
     * 例如：录入【任务开始时间】、【任务结束时间】，通过HOURS函数自动填入【耗时】小时数。
     */
    HOURS("date", "HOURS"),
    /**
     * 语法：MINUTES(endDate,startDate)
     * 说明：返回两个时间之间的分钟数，精确到两位小数。end_time为结束时间，start_time为开始时间
     * 例如：录入【任务开始时间】、【任务结束时间】，通过MINUTES函数自动填入【耗时】分钟数。
     */
    MINUTES("date", "MINUTES"),
    /**
     * 语法：NOW()
     * 说明：返回当前时间，精确到时分秒，格式为yyyy-MM-dd hh:mm:ss
     * 例如：显示当前操作的时间。
     */
    NOW("date", "NOW"),
    /**
     * 语法：ADDDAY(date,days)
     * 说明： 将指定日期加/减指定天数，date为指定日期，days为指定天数，当为负数时在date上减去此天数
     * 例如：录入【项目开始时间】、【项目预计天数】，通过ADDDAY函数自动填入【项目预计完成时间】。
     */
    ADDDAY("date", "ADDDAY"),
    /**
     * 语法：ADDMONTH(date,months)
     * 说明：将指定日期加/减指定月数，date为指定日期，months为指定月数，当为负数时在此date上减去此月数
     * 例如：录入【项目开始时间】、【项目预计月数】，通过ADDMONTH函数自动填入【项目预计完成时间】。
     */
    ADDMONTH("date", "ADDMONTH"),
    /**
     * 语法：ADDYEAR(date,years)
     * 说明：将指定日期加/减指定年数，date为指定日期，years为指定年数，当为负数时在此date上减去此年数
     * 例如：录入【合同开始时间】、【合同有效年限】，通过ADDYEAR函数自动填入【合同到期时间】。
     */
    ADDYEAR("date", "ADDYEAR"),

    /**
     * 时间戳转换为日期对象
     * 语法：DATE(year,month,day,[hour,minute,second])
     * 说明：将年月日时分秒转换为日期
     * 例如：手动固定某一个时间 。
     * */
    DATE("date", "DATE"),
    /**
     * DATEDELTA(timestamp, deltadays)
     * 将指定日期加/减指定天数。
     * timestamp: 必需。初始日期。
     * deltadays: 必需。需要加减的天数。正数为增加，负数为减少。
     */
    DATEDELTA("date", "DATEDELTA"),

    /**
     * 语法：YEAR(date)
     * 说明：返回日期date的年份
     * 例如：录入【入学时间】，通过YEAR函数自动填入【年级】。
     */
    YEAR("date", "YEAR"),
    /**
     * 语法：MONTH(date)
     * 说明：返回日期date月份，值为介于1到12之间的整数
     * 例如：录入【入学时间】，通过MONTH函数自动填入【入学月份】。
     */
    MONTH("date", "MONTH"),
    /**
     * DAY函数可以获取某日期是当月的第几日
     * 用法：DAY(时间戳)
     */
    DAY("date", "DAY"),

    /**
     * HOUR函数可以返回某日期的小时数
     * 用法：HOUR(时间戳)
     */
    HOUR("date", "HOUR"),
    /**
     * 语法：MINUTE(time)
     * 说明：返回日期time的分钟部分
     * 例如：录入【任务时间】，通过DAY函数自动填入【具体分钟】。
     */
    MINUTE("date", "MINUTE"),
    /**
     * 语法：QUARTER(date)
     * 说明：返回日期date的所属季度，值为介于1到4的整数
     * 例如：录入【填写时间】，通过DAY函数自动填入【季度】。
     */
    QUARTER("date", "QUARTER"),
    /**
     * 语法：TODAY()
     * 说明：返回今天的日期，格式为:yyyy-MM-dd
     * 例如：客户跟进需要多次记录填写时间，通过TODAY函数自动填入【日期】。
     */
    TODAY("date", "TODAY"),
    /**
     * 语法：WEEKDAY(date)
     * 说明：返回指定日期date为星期几
     * 例如：录入【填写日期】，通过WEEKDAY函数自动填入【星期】。
     */
    WEEKDAY("date", "WEEKDAY"),
    /**
     * 语法：WEEKNUM(date)
     * 说明：返回一个数字，该数字代表指定日期date是一年中的第几周
     * 例如：根据系统生成的创建时间，通过WEEKNUM函数自动填入【周】。
     */
    WEEKNUM("date", "WEEKNUM"),
    /**
     * TIMESTAMP(date)
     * 将日期对象转换成时间戳。
     */
    TIMESTAMP("date", "TIMESTAMP"),
    /**
     * TIME(hour, minute, second)
     * 返回特定时间的十进制数字。时间值为日期值的一部分，并用十进制数表示（例如 12:00 PM 可表示为 0.5，因为此时是一天的一半）。
     * hour: 必需。 0（零）到 32767 之间的数字，代表小时。 任何大于 23 的值都会除以 24，余数将作为小时值。 例如，TIME(27,0,0) = TIME(3,0,0) = .125
     * minute: 必需。 0 到 32767 之间的数字，代表分钟。 任何大于 59 的值将转换为小时和分钟。 例如，TIME(0,750,0) = TIME(12,30,0) = .520833
     * second: 必需。 0 到 32767 之间的数字，代表秒。 任何大于 59 的值将转换为小时、分钟和秒。 例如，TIME(0,0,2000) = TIME(0,33,20) = .023148
     */
    TIME("date", "TIME"),
    /**
     * SYSTIME()
     * 返回当前服务器时间。
     * 即使客户端的时间被人为调整了，SYSTIME函数不受影响，获取的仍然是服务器时间。例如签到、打卡等场景下，可避免调整时间作弊的情况。
     * 语法：SYSTIME()
     * 说明：返回服务器时间，精确到秒
     */
    SYSTIME("date", "SYSTIME"),
    /**
     * SYSTIMEMS()
     * 返回当前服务器时间(毫秒)。
     * 即使客户端的时间被人为调整了，SYSTIMEMS函数不受影响，获取的仍然是服务器时间。例如签到、打卡等场景下，可避免调整时间作弊的情况。
     * 语法：SYSTIMEMS()
     * 说明：返回服务器时间，精确到秒
     */
    SYSTIMEMS("date", "SYSTIMEMS"),
    /**
     * 语法：SECOND(timestamp)
     * 说明： 返回某日期的秒数。
     */
    SECOND("date", "SECOND"),
    /**
     * DAYS360按照一年 360 天的算法，返回两个日期间相差的天数
     * 用法：DAYS360(结束日期,开始日期)
     * DAYS360(end_timestamp, start_timestamp, method)
     * 按照一年 360 天的算法（每个月以 30 天计，一年共计 12 个月），DAYS360 函数返回两个日期间相差的天数，这在一些会计计算中将会用到。 如果财会系统是基于一年 12 个月，每月 30 天，可使用此函数帮助计算支付款项。
     * end_timestamp: 必需。结束日期。
     * start_timestamp: 必需。起始日期。
     * method: 可选。用于指定在计算中是采用美国方法还是欧洲方法。不填或false表示是美国方法，true表示是欧洲方法。
     */
    DAYS360("date", "DAYS360"),
    /**
     * 计算一个时间段在某年内的相交天数
     * 用法：ONEYEARRANGDAY(开始日期, 结束日期, 某一年)
     * ONEYEARRANGDAY(start_timestamp,end_timestamp, year)
     * 计算一个时间段在某年内的相交天数
     * end_timestamp: 必需。结束日期。
     * start_timestamp: 必需。起始日期。
     * year: 年份 必需
     */
    ONEYEARRANGDAY("date", "ONEYEARRANGDAY"),
    /**
     * 周数计算
     * ISOWEEKNUM(timestamp)
     * 返回给定日期在全年中的ISO周数。
     * timestamp: 必需。日期是Excel用于日期和时间计算的日期-时间代码
     */
    ISOWEEKNUM("date", "ISOWEEKNUM"),
    /**
     * UUID函数随机码生成器。可适用于随机流水号的使用场景等
     */
    UUID("advanced", "UUID"),
    GUID("advanced", "GUID"),
    ;

    private String formula;

    /**
     * 类型：
     */
    private String type;

    MathEnum(String type){
        this.type = type;
    }

    MathEnum(String type, String formula){
        this.type = type;
        this.formula = formula;
    }

    public String getType() {
        return type;
    }

    public String getFormula(){
        return formula;
    }

    public static boolean hasFormula(String express) {
        for (MathEnum mathEnum: values()) {
            if (express.contains(mathEnum.getFormula())) {
                return true;
            }
        }
        return false;
    }
}
